expander
Expands a proc-macro into a file, and uses a include!
directive in place.
Advantages
- Only expands a particular proc-macro, not all of them. I.e.
tracing
is notorious for expanding into a significant amount of boilerplate with i.e.cargo expand
- Get good errors when your generated code is not perfect yet
Usage
In your proc-macro
, use it like:
// or any other macro type
will expand into
include!;
where the file content will be
Exemplary output
An error in your proc-macro, i.e. an excess ;
, is shown as
becomes
which shows exactly where in the generated code, the produce of your proc-macro, rustc found an invalid token sequence.
Now this was a simple example, doing this with macros that would expand to multiple tens of thousand lines of
code when expanded with cargo-expand
, and still in a few thousand that your particular one generates, it's a
life saver to know what caused the issue rather than having to use eprintln!
to print a unformated
string to the terminal.
Hint: You can quickly toggle this by using
.dry(true || false)
Features
Special handling: syn
By default expander
is built with feature syndicate
which adds fn maybe_write_*
to struct Expander
, which aids handling of Result<TokenStream, syn::Error>
for the
commonly used rust parsing library syn
.
Reasoning
syn::Error::new(Span::call_site(),"yikes!").into_token_stream(self)
becomes compile_error!("yikes!")
which provides better info to the user (that's you!) than when serializing it to file, since the provided
span
for the syn::Error
is printed differently - being pointed to the compile_error!
invocation
in the generated file is not helpful, and rustc
can point to the span
instead.
rustfmt
-free formatting: pretty
When built with feature pretty
, the output is formatted with prettier-please
. Note that this adds
additional compiletime overhead and weight to the crate as a trade off not needing any host side tooling.
The formatting output will, for any significant amount of lines of code, differ from the output of rustfmt
.